/**
 * @copyright Copyright (c) 2025 CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author Xie Jinhui
 */

#include "main.h"

/**
 * @brief Safe flush function to clear input buffer
 * 
 * This function safely flushes the input buffer by reading characters
 * until EOF or newline is encountered, preventing buffer overflow issues
 * 
 * @param fp File pointer to the input stream to be flushed
 */
static void safe_flush(FILE *fp)
{
    int ch;
    /* 
     * Read characters one by one from the input stream 
     * Continue until EOF is reached or newline character is found
     */
    while ((ch = fgetc(fp)) != EOF && ch != '\n')
        ;
}

/**
 * @brief Save APN configuration to persistent storage
 * 
 * This function saves the current APN configuration to the configuration file
 * It handles both carrier-specific APNs and default APN configurations
 * Validates input parameters and maintains configuration integrity
 * 
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
static uint8_t save_apnConfig(void)
{
    /* Static buffer to hold JSON configuration string */
    static uint8_t CONFIG_STRING[JSON_LEN] = {0};
    /* Buffer for writing formatted JSON configuration */
    char config_write_buff[JSON_LEN] = {0};

    /* cJSON objects for parsing and manipulating configuration */
    cJSON *config = NULL;
    cJSON *device_item = NULL;
    cJSON *carrier_item = NULL;
    cJSON *carrier_apn = NULL;
    /* Variables to track array sizes for validation */
    int carrier_apn_num = 0;
    int carrier_user_num = 0;
    int carrier_passd_num = 0;
    cJSON *carrier_user = NULL;
    cJSON *carrier_passd = NULL;

    /* Initialize carrier flag to indicate non-carrier specific APN */
    apnMsg.carrier_flag = 0;

    /* Clear configuration string buffer before use */
    memset(CONFIG_STRING, 0x00, sizeof(CONFIG_STRING));
    /* Retrieve current configuration from storage */
    if (!getConfig(CONFIG_STRING, CONFIG_APN))
    {
        printf("ERROR: getConfig failed!\n");
        return FALSE;
    }

    /* Parse JSON configuration string into cJSON object */
    config = string2Json(CONFIG_STRING);

    /* Validate that configuration was parsed correctly and is an object */
    if ((config == NULL) || (config->type != cJSON_Object))
    {
        printf("ERROR: getConfig failed!\n");
        cJSON_Delete(config);
        return FALSE;
    }

    /* Validate device name is provided */
    if (apnMsg.dev == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Validate device name is either ppp0 or ppp1 */
    if (strcmp(apnMsg.dev, "ppp0") && strcmp(apnMsg.dev, "ppp1"))
    {
        printf("ERROR: getConfig dev failed!\n");
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get the device-specific configuration object */
    device_item = cJSON_GetObjectItem(config, apnMsg.dev);

    /* Validate device configuration exists and is an array */
    if ((device_item == NULL) && (device_item->type != cJSON_Array))
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Check if carrier name matches known carriers and set flag accordingly */
    if (!strcmp(apnMsg.carrier_name, MOBILE_CARRIER) || !strcmp(apnMsg.carrier_name, UNICOM_CARRIER) ||
        !strcmp(apnMsg.carrier_name, TELECOM_CARRIER))
    {
        apnMsg.carrier_flag = 1;
    }

    /* Process configuration based on carrier flag */
    switch (apnMsg.carrier_flag)
    {
    case 1:
        /* Handle carrier-specific APN configuration */
        carrier_item = cJSON_GetObjectItem(device_item, apnMsg.carrier_name);
        if (carrier_item == NULL)
        {
            cJSON_Delete(config);
            return FALSE;
        }

        /* Get APN array for the specified carrier */
        carrier_apn = cJSON_GetObjectItem(carrier_item, "apn");
        if (carrier_apn == NULL)
        {
            cJSON_Delete(config);
            return FALSE;
        }

        /* Get username array for the specified carrier */
        carrier_user = cJSON_GetObjectItem(carrier_item, "user");
        if (carrier_user == NULL)
        {
            cJSON_Delete(config);
            return FALSE;
        }

        /* Get password array for the specified carrier */
        carrier_passd = cJSON_GetObjectItem(carrier_item, "passd");
        if (carrier_passd == NULL)
        {
            cJSON_Delete(config);
            return FALSE;
        }

        /* Validate array sizes to prevent exceeding maximum limits */
        carrier_apn_num = cJSON_GetArraySize(carrier_apn);
        carrier_user_num = cJSON_GetArraySize(carrier_user);
        carrier_passd_num = cJSON_GetArraySize(carrier_passd);
        if ((carrier_apn_num >= 4) || (carrier_user_num >= 4) || (carrier_passd_num >= 4))
        {
            printf("ERROR: The number of %s's apn exceeds 4\n", apnMsg.carrier_name);
            cJSON_Delete(config);
            return FALSE;
        }

        /* Add new APN configuration to carrier-specific arrays */
        cJSON_AddItemReferenceToArray(carrier_apn, cJSON_CreateString(apnMsg.apn));
        cJSON_AddItemReferenceToArray(carrier_user, cJSON_CreateString(apnMsg.user));
        cJSON_AddItemReferenceToArray(carrier_passd, cJSON_CreateString(apnMsg.password));
        break;

    default:
        /* Handle default APN configuration (non-carrier specific) */
        /* Replace default APN configuration in device object */
        cJSON_ReplaceItemInObject(device_item, "apn", cJSON_CreateString(apnMsg.apn));
        cJSON_ReplaceItemInObject(device_item, "user", cJSON_CreateString(apnMsg.user));
        cJSON_ReplaceItemInObject(device_item, "passd", cJSON_CreateString(apnMsg.password));
        break;
    }

    /* Clear write buffer before generating JSON string */
    memset(config_write_buff, 0x00, sizeof(config_write_buff));
    int size = sizeof(config_write_buff);
    /* Generate formatted JSON string with proper formatting */
    cJSON_PrintPreallocated(config, config_write_buff, (const int)size, 1);

    /* Write updated configuration back to storage */
    if (write_file(CONFIG_APN, config_write_buff) < 0)
    {
        printf("ERROR: save_apnConfig error!\n");
        cJSON_Delete(config);
        return FALSE;
    }

    /* Clean up cJSON objects to prevent memory leaks */
    cJSON_Delete(config);

    return TRUE;
}

/**
 * @brief Retrieve APN configuration from persistent storage
 * 
 * This function reads the APN configuration from the configuration file
 * and populates the global apnMsg structure with the retrieved data
 * Handles both ppp0 and ppp1 interfaces with their carrier-specific APNs
 * 
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
static uint8_t get_apnConfig(void)
{
    /* Static buffer to hold JSON configuration string */
    static uint8_t CONFIG_STRING[JSON_LEN] = {0};

    /* Clear configuration string buffer before use */
    memset(CONFIG_STRING, 0x00, JSON_LEN);

    /* Retrieve configuration from storage */
    if (!getConfig(CONFIG_STRING, CONFIG_APN))
    {
        printf("ERROR: getConfig failed!\n");
        return FALSE;
    }

    /* Parse JSON configuration string into cJSON object */
    cJSON *config = string2Json(CONFIG_STRING);
    if (config == NULL)
    {
        return FALSE;
    }

    /**
     * @brief Process ppp0 interface configuration
     */
    /* Get ppp0 configuration object from root configuration */
    cJSON *ppp0_item = cJSON_GetObjectItem(config, "ppp0");
    if (ppp0_item == NULL)
    {
        printf("ERROR: ppp0_item is NULL!\n");
        cJSON_Delete(config);
        return FALSE;
    }
    /* Extract default APN configuration for ppp0 */
    if (cJSON_GetObjectItem(ppp0_item, "apn") != NULL)
    {
        strcpy(apnMsg.ppp0.apn, cJSON_GetObjectItem(ppp0_item, "apn")->valuestring);
    }
    /* Extract default username for ppp0 */
    if (cJSON_GetObjectItem(ppp0_item, "user") != NULL)
    {
        strcpy(apnMsg.ppp0.user, cJSON_GetObjectItem(ppp0_item, "user")->valuestring);
    }
    /* Extract default password for ppp0 */
    if (cJSON_GetObjectItem(ppp0_item, "passd") != NULL)
    {
        strcpy(apnMsg.ppp0.password, cJSON_GetObjectItem(ppp0_item, "passd")->valuestring);
    }

    /* Process Mobile carrier APNs for ppp0 */
    cJSON *ppp0_Mobile = cJSON_GetObjectItem(ppp0_item, "Mobile");
    if (ppp0_Mobile == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier APN array */
    cJSON *ppp0_Mobile_apn = cJSON_GetObjectItem(ppp0_Mobile, "apn");
    if (ppp0_Mobile_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier username array */
    cJSON *ppp0_Mobile_user = cJSON_GetObjectItem(ppp0_Mobile, "user");
    if (ppp0_Mobile_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier password array */
    cJSON *ppp0_Mobile_passd = cJSON_GetObjectItem(ppp0_Mobile, "passd");
    if (ppp0_Mobile_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Mobile carrier APN configurations */
    apnMsg.ppp0.Mobile.apn_num = cJSON_GetArraySize(ppp0_Mobile_apn);
    for (int i = 0; i < apnMsg.ppp0.Mobile.apn_num; i++)
    {
        strcpy(apnMsg.ppp0.Mobile.apn[i], (char *)(cJSON_GetArrayItem(ppp0_Mobile_apn, i)->valuestring));
        strcpy(apnMsg.ppp0.Mobile.user[i], (char *)(cJSON_GetArrayItem(ppp0_Mobile_user, i)->valuestring));
        strcpy(apnMsg.ppp0.Mobile.password[i], (char *)(cJSON_GetArrayItem(ppp0_Mobile_passd, i)->valuestring));
    }

    /* Process Unicom carrier APNs for ppp0 */
    cJSON *ppp0_Unicom = cJSON_GetObjectItem(ppp0_item, "Unicom");
    if (ppp0_Unicom == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier APN array */
    cJSON *ppp0_Unicom_apn = cJSON_GetObjectItem(ppp0_Unicom, "apn");
    if (ppp0_Unicom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier username array */
    cJSON *ppp0_Unicom_user = cJSON_GetObjectItem(ppp0_Unicom, "user");
    if (ppp0_Unicom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier password array */
    cJSON *ppp0_Unicom_passd = cJSON_GetObjectItem(ppp0_Unicom, "passd");
    if (ppp0_Unicom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Unicom carrier APN configurations */
    apnMsg.ppp0.Unicom.apn_num = cJSON_GetArraySize(ppp0_Unicom_apn);
    for (int i = 0; i < apnMsg.ppp0.Unicom.apn_num; i++)
    {
        strcpy(apnMsg.ppp0.Unicom.apn[i], (char *)(cJSON_GetArrayItem(ppp0_Unicom_apn, i)->valuestring));
        strcpy(apnMsg.ppp0.Unicom.user[i], (char *)(cJSON_GetArrayItem(ppp0_Unicom_user, i)->valuestring));
        strcpy(apnMsg.ppp0.Unicom.password[i], (char *)(cJSON_GetArrayItem(ppp0_Unicom_passd, i)->valuestring));
    }

    /* Process Telecom carrier APNs for ppp0 */
    cJSON *ppp0_Telecom = cJSON_GetObjectItem(ppp0_item, "Telecom");
    if (ppp0_Telecom == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier APN array */
    cJSON *ppp0_Telecom_apn = cJSON_GetObjectItem(ppp0_Telecom, "apn");
    if (ppp0_Telecom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier username array */
    cJSON *ppp0_Telecom_user = cJSON_GetObjectItem(ppp0_Telecom, "user");
    if (ppp0_Telecom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier password array */
    cJSON *ppp0_Telecom_passd = cJSON_GetObjectItem(ppp0_Telecom, "passd");
    if (ppp0_Telecom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Telecom carrier APN configurations */
    apnMsg.ppp0.Telecom.apn_num = cJSON_GetArraySize(ppp0_Telecom_apn);
    for (int i = 0; i < apnMsg.ppp0.Telecom.apn_num; i++)
    {
        strcpy(apnMsg.ppp0.Telecom.apn[i], (char *)(cJSON_GetArrayItem(ppp0_Telecom_apn, i)->valuestring));
        strcpy(apnMsg.ppp0.Telecom.user[i], (char *)(cJSON_GetArrayItem(ppp0_Telecom_user, i)->valuestring));
        strcpy(apnMsg.ppp0.Telecom.password[i], (char *)(cJSON_GetArrayItem(ppp0_Telecom_passd, i)->valuestring));
    }

    /**
     * @brief Process ppp1 interface configuration
     */
    /* Get ppp1 configuration object from root configuration */
    cJSON *ppp1_item = cJSON_GetObjectItem(config, "ppp1");
    if (ppp1_item == NULL)
    {
        printf("ERROR: ppp1_item is NULL!\n");
        cJSON_Delete(config);
        return FALSE;
    }
    /* Extract default APN configuration for ppp1 */
    if (cJSON_GetObjectItem(ppp1_item, "apn") != NULL)
    {
        strcpy(apnMsg.ppp1.apn, cJSON_GetObjectItem(ppp1_item, "apn")->valuestring);
    }
    /* Extract default username for ppp1 */
    if (cJSON_GetObjectItem(ppp1_item, "user") != NULL)
    {
        strcpy(apnMsg.ppp1.user, cJSON_GetObjectItem(ppp1_item, "user")->valuestring);
    }
    /* Extract default password for ppp1 */
    if (cJSON_GetObjectItem(ppp1_item, "passd") != NULL)
    {
        strcpy(apnMsg.ppp1.password, cJSON_GetObjectItem(ppp1_item, "passd")->valuestring);
    }

    /* Process Mobile carrier APNs for ppp1 */
    cJSON *ppp1_Mobile = cJSON_GetObjectItem(ppp1_item, "Mobile");
    if (ppp1_Mobile == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier APN array for ppp1 */
    cJSON *ppp1_Mobile_apn = cJSON_GetObjectItem(ppp1_Mobile, "apn");
    if (ppp1_Mobile_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier username array for ppp1 */
    cJSON *ppp1_Mobile_user = cJSON_GetObjectItem(ppp1_Mobile, "user");
    if (ppp1_Mobile_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier password array for ppp1 */
    cJSON *ppp1_Mobile_passd = cJSON_GetObjectItem(ppp1_Mobile, "passd");
    if (ppp1_Mobile_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Mobile carrier APN configurations for ppp1 */
    apnMsg.ppp1.Mobile.apn_num = cJSON_GetArraySize(ppp1_Mobile_apn);
    for (int i = 0; i < apnMsg.ppp1.Mobile.apn_num; i++)
    {
        strcpy(apnMsg.ppp1.Mobile.apn[i], (char *)(cJSON_GetArrayItem(ppp1_Mobile_apn, i)->valuestring));
        strcpy(apnMsg.ppp1.Mobile.user[i], (char *)(cJSON_GetArrayItem(ppp1_Mobile_user, i)->valuestring));
        strcpy(apnMsg.ppp1.Mobile.password[i], (char *)(cJSON_GetArrayItem(ppp1_Mobile_passd, i)->valuestring));
    }

    /* Process Unicom carrier APNs for ppp1 */
    cJSON *ppp1_Unicom = cJSON_GetObjectItem(ppp1_item, "Unicom");
    if (ppp1_Unicom == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier APN array for ppp1 */
    cJSON *ppp1_Unicom_apn = cJSON_GetObjectItem(ppp1_Unicom, "apn");
    if (ppp1_Unicom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier username array for ppp1 */
    cJSON *ppp1_Unicom_user = cJSON_GetObjectItem(ppp1_Unicom, "user");
    if (ppp1_Unicom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier password array for ppp1 */
    cJSON *ppp1_Unicom_passd = cJSON_GetObjectItem(ppp1_Unicom, "passd");
    if (ppp1_Unicom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Unicom carrier APN configurations for ppp1 */
    apnMsg.ppp1.Unicom.apn_num = cJSON_GetArraySize(ppp1_Unicom_apn);
    for (int i = 0; i < apnMsg.ppp1.Unicom.apn_num; i++)
    {
        strcpy(apnMsg.ppp1.Unicom.apn[i], (char *)(cJSON_GetArrayItem(ppp1_Unicom_apn, i)->valuestring));
        strcpy(apnMsg.ppp1.Unicom.user[i], (char *)(cJSON_GetArrayItem(ppp1_Unicom_user, i)->valuestring));
        strcpy(apnMsg.ppp1.Unicom.password[i], (char *)(cJSON_GetArrayItem(ppp1_Unicom_passd, i)->valuestring));
    }

    /* Process Telecom carrier APNs for ppp1 */
    cJSON *ppp1_Telecom = cJSON_GetObjectItem(ppp1_item, "Telecom");
    if (ppp1_Telecom == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier APN array for ppp1 */
    cJSON *ppp1_Telecom_apn = cJSON_GetObjectItem(ppp1_Telecom, "apn");
    if (ppp1_Telecom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier username array for ppp1 */
    cJSON *ppp1_Telecom_user = cJSON_GetObjectItem(ppp1_Telecom, "user");
    if (ppp1_Telecom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier password array for ppp1 */
    cJSON *ppp1_Telecom_passd = cJSON_GetObjectItem(ppp1_Telecom, "passd");
    if (ppp1_Telecom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Extract all Telecom carrier APN configurations for ppp1 */
    apnMsg.ppp1.Telecom.apn_num = cJSON_GetArraySize(ppp1_Telecom_apn);
    for (int i = 0; i < apnMsg.ppp1.Telecom.apn_num; i++)
    {
        strcpy(apnMsg.ppp1.Telecom.apn[i], (char *)(cJSON_GetArrayItem(ppp1_Telecom_apn, i)->valuestring));
        strcpy(apnMsg.ppp1.Telecom.user[i], (char *)(cJSON_GetArrayItem(ppp1_Telecom_user, i)->valuestring));
        strcpy(apnMsg.ppp1.Telecom.password[i], (char *)(cJSON_GetArrayItem(ppp1_Telecom_passd, i)->valuestring));
    }

    /* Clean up cJSON objects to prevent memory leaks */
    cJSON_Delete(config);
    return TRUE;
}

/**
 * @brief Initialize carrier-specific APN arrays in configuration file
 * 
 * This function resets all carrier-specific APN arrays to empty arrays
 * Used for initialization or reset of carrier APN configurations
 * Creates empty arrays for Mobile, Unicom, and Telecom carriers for both ppp0 and ppp1
 * 
 * @param file_string The current configuration file content as string
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
uint8_t config_file_apn_Init(char *file_string)
{
    /* Buffer for writing formatted JSON configuration */
    char config_write_buff[JSON_LEN] = {0};

    /* Parse the input configuration string into cJSON object */
    cJSON *config_file = cJSON_Parse(file_string);
    if (config_file == NULL)
    {
        cJSON_Delete(config_file);
        return FALSE;
    }

    /* Get ppp0 configuration object */
    cJSON *ppp0_item = cJSON_GetObjectItem(config_file, "ppp0");
    if (ppp0_item == NULL)
    {
        cJSON_Delete(config_file);
        return FALSE;
    }

    /* Get ppp1 configuration object */
    cJSON *ppp1_item = cJSON_GetObjectItem(config_file, "ppp1");
    if (ppp1_item == NULL)
    {
        cJSON_Delete(config_file);
        return FALSE;
    }

    // Rewrite configuration file with initialized carrier arrays
    // Create new carrier objects with empty arrays
    
    /* Create Mobile carrier object with empty APN, user, and password arrays */
    cJSON *Mobile = cJSON_CreateObject();
    if (Mobile != NULL)
    {
        cJSON_AddItemToObject(Mobile, "apn", cJSON_CreateArray());
        cJSON_AddItemToObject(Mobile, "user", cJSON_CreateArray());
        cJSON_AddItemToObject(Mobile, "passd", cJSON_CreateArray());
    }

    /* Create Unicom carrier object with empty APN, user, and password arrays */
    cJSON *Unicom = cJSON_CreateObject();
    if (Unicom != NULL)
    {
        cJSON_AddItemToObject(Unicom, "apn", cJSON_CreateArray());
        cJSON_AddItemToObject(Unicom, "user", cJSON_CreateArray());
        cJSON_AddItemToObject(Unicom, "passd", cJSON_CreateArray());
    }

    /* Create Telecom carrier object with empty APN, user, and password arrays */
    cJSON *Telecom = cJSON_CreateObject();
    if (Telecom != NULL)
    {
        cJSON_AddItemToObject(Telecom, "apn", cJSON_CreateArray());
        cJSON_AddItemToObject(Telecom, "user", cJSON_CreateArray());
        cJSON_AddItemToObject(Telecom, "passd", cJSON_CreateArray());
    }

    /* Add carrier objects to ppp0 configuration */
    cJSON_AddItemToObject(ppp0_item, "Mobile", Mobile);
    cJSON_AddItemToObject(ppp0_item, "Unicom", Unicom);
    cJSON_AddItemToObject(ppp0_item, "Telecom", Telecom);

    /* Add carrier objects to ppp1 configuration */
    cJSON_AddItemToObject(ppp1_item, "Mobile", Mobile);
    cJSON_AddItemToObject(ppp1_item, "Unicom", Unicom);
    cJSON_AddItemToObject(ppp1_item, "Telecom", Telecom);

    /* Clear write buffer before generating JSON string */
    memset(config_write_buff, 0x00, sizeof(config_write_buff));
    int size = sizeof(config_write_buff);
    /* Generate formatted JSON string with proper formatting */
    cJSON_PrintPreallocated(config_file, config_write_buff, (const int)size, 1);
    // printf("config_write_buff:%s\n", config_write_buff);

    /* Write updated configuration back to storage */
    if (write_file(CONFIG_APN, config_write_buff) < 0)
    {
        printf("ERROR: config_file_apn_Init error!\n");
        cJSON_Delete(config_file);
        return FALSE;
    }

    // cJSON_Delete(config_file);

    return TRUE;
}

/**
 * @brief Add a new APN configuration through user interaction
 * 
 * This function provides an interactive interface for users to add new APN configurations
 * It collects APN details from user input, validates them, and saves the configuration
 * Supports both ppp0 and ppp1 interfaces with proper SIM slot mapping
 * 
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
uint8_t wwwan_apn_add(void)
{
    /* Clear APN message structure before collecting new data */
    memset(apnMsg.dev, 0x00, APN_NAME_LEN);
    memset(apnMsg.user, 0x00, APN_NAME_LEN);
    memset(apnMsg.apn, 0x00, APN_NAME_LEN);
    memset(apnMsg.password, 0x00, APN_NAME_LEN);

    /* Inform user that APN configuration is starting */
    printf("start config apn\n");

    /* Collect APN name from user input with length validation */
    printf("Enter apn name(1-99): ");
    fflush(stdout);
    scanf("%[^\n]", apnMsg.apn);
    safe_flush(stdin);
    /* Collect username from user input with length validation */
    printf("Enter user name(0-64): ");
    fflush(stdout);
    scanf("%[^\n]", apnMsg.user);
    safe_flush(stdin);
    /* Collect password from user input with length validation */
    printf("Enter password(0-32): ");
    fflush(stdout);
    scanf("%[^\n]", apnMsg.password);
    safe_flush(stdin);
    /* Collect device name from user input (ppp0 or ppp1) */
    printf("Enter dev name(ppp0/ppp1): ");
    fflush(stdout);
    scanf("%[^\n]", apnMsg.dev);
    safe_flush(stdin);

    /* Validate input lengths to prevent buffer overflow and ensure data integrity */
    if ((strlen(apnMsg.apn) > 99) || (strlen(apnMsg.user) > 64) || (strlen(apnMsg.password) > 32))
    {
        printf("ERROR: Input byte length out of range.\n");
        return FALSE;
    }

    /* Validate that APN name is not empty */
    if (strlen(apnMsg.apn) < 1)
    {
        printf("ERROR: APN name length must more than 1.\n");
        return FALSE;
    }

    /* Prepare configuration structure for system APN configuration */
    configAPNInfo configInfo;
    char status[16] = {0};
    /* Map device name to SIM slot for system configuration */
    if (!strcmp(apnMsg.dev, "ppp0"))
    {
        strcpy(configInfo.simSlot, "sim1");
    }
    else if (strcmp(apnMsg.dev, "ppp1"))
    {
        strcpy(configInfo.simSlot, "sim2");
    }
    else
    {
        printf("ERROR: config apn error!\n");
        return FALSE;
    }

    /* Copy APN details to configuration structure */
    strcpy(configInfo.apnName, apnMsg.apn);
    strcpy(configInfo.apnPsw, apnMsg.password);
    strcpy(configInfo.apnUser, apnMsg.user);

    /* Apply APN configuration to system and check for success */
    if (!get_configAPN(&configInfo, status) || !strcmp(status, "FAILURE"))
    {
        printf("ERROR: config apn error!\n");
        return FALSE;
    }

    // Save configuration to local sim_config.json file for persistence
    if (!save_apnConfig())
    {
        printf("ERROR: save_apnConfig error!\n");
    }

    return TRUE;
}

/**
 * @brief Display APN configurations for specified device or all devices
 * 
 * This function retrieves and displays APN configurations in a formatted table
 * Shows both default APNs and carrier-specific APNs with their details
 * Supports displaying configurations for ppp0, ppp1, or all devices
 * 
 * @param dev Device name to display ("ppp0", "ppp1", or "all")
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
uint8_t wwan_apn_show(char *dev)
{
    /* Retrieve APN configuration from storage */
    if (!get_apnConfig())
    {
        printf("ERROR: get_apnConfig error!\n");
        return FALSE;
    }

    /* Display configurations based on specified device */
    if (!strcmp(dev, "ppp0"))
    {
        /* Display ppp0 interface APN configurations */
        int j = 1;
        /* Print table header */
        printf("dev_name\tType    \tnum\tapn_name\tuser_name\tpassword\n");
        /* Display default APN configuration */
        printf(" ppp0    \tdefault \t-\t%-15s\t%-15s\t%s\n", apnMsg.ppp0.apn, apnMsg.ppp0.user, apnMsg.ppp0.password);
        /* Display all Mobile carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Mobile.apn_num; i++)
        {
            printf(" ppp0    \tMobile  \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Mobile.apn[i],
                   apnMsg.ppp0.Mobile.user[i], apnMsg.ppp0.Mobile.password[i]);
            j++;
        }

        /* Display all Unicom carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Unicom.apn_num; i++)
        {
            printf(" ppp0    \tUnicom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Unicom.apn[i],
                   apnMsg.ppp0.Unicom.user[i], apnMsg.ppp0.Unicom.password[i]);
            j++;
        }

        /* Display all Telecom carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Telecom.apn_num; i++)
        {
            printf(" ppp0    \tTelecom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Telecom.apn[i],
                   apnMsg.ppp0.Telecom.user[i], apnMsg.ppp0.Telecom.password[i]);
            j++;
        }
    }
    else if (!strcmp(dev, "ppp1"))
    {
        /* Display ppp1 interface APN configurations */
        int j = 1;
        /* Print table header */
        printf("dev_name\tType    \tnum\tapn_name\tuser_name\tpassword\n");
        /* Display default APN configuration */
        printf(" ppp1    \tdefault \t-\t%-15s\t%-15s\t%s\n", apnMsg.ppp1.apn, apnMsg.ppp1.user, apnMsg.ppp1.password);
        /* Display all Mobile carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Mobile.apn_num; i++)
        {
            printf(" ppp1    \tMobile  \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Mobile.apn[i],
                   apnMsg.ppp1.Mobile.user[i], apnMsg.ppp1.Mobile.password[i]);
            j++;
        }

        /* Display all Unicom carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Unicom.apn_num; i++)
        {
            printf(" ppp1    \tUnicom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Unicom.apn[i],
                   apnMsg.ppp1.Unicom.user[i], apnMsg.ppp1.Unicom.password[i]);
            j++;
        }

        /* Display all Telecom carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Telecom.apn_num; i++)
        {
            printf(" ppp1    \tTelecom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Telecom.apn[i],
                   apnMsg.ppp1.Telecom.user[i], apnMsg.ppp1.Telecom.password[i]);
            j++;
        }
    }
    else if (!strcmp(dev, "all"))
    {
        /* Display APN configurations for both ppp0 and ppp1 interfaces */
        int j = 1;
        // PPP0 configurations
        /* Print table header */
        printf("dev_name\tType    \tnum\tapn_name\tuser_name\tpassword\n");
        /* Display ppp0 default APN configuration */
        printf(" ppp0    \tdefault \t-\t%-15s\t%-15s\t%s\n", apnMsg.ppp0.apn, apnMsg.ppp0.user, apnMsg.ppp0.password);
        /* Display all ppp0 Mobile carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Mobile.apn_num; i++)
        {
            printf(" ppp0    \tMobile  \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Mobile.apn[i],
                   apnMsg.ppp0.Mobile.user[i], apnMsg.ppp0.Mobile.password[i]);
            j++;
        }

        /* Display all ppp0 Unicom carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Unicom.apn_num; i++)
        {
            printf(" ppp0    \tUnicom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Unicom.apn[i],
                   apnMsg.ppp0.Unicom.user[i], apnMsg.ppp0.Unicom.password[i]);
            j++;
        }

        /* Display all ppp0 Telecom carrier APNs */
        for (int i = 0; i < apnMsg.ppp0.Telecom.apn_num; i++)
        {
            printf(" ppp0    \tTelecom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp0.Telecom.apn[i],
                   apnMsg.ppp0.Telecom.user[i], apnMsg.ppp0.Telecom.password[i]);
            j++;
        }

        // PPP1 configurations
        /* Display ppp1 default APN configuration */
        printf(" ppp1    \tdefault \t-\t%-15s\t%-15s\t%s\n", apnMsg.ppp1.apn, apnMsg.ppp1.user, apnMsg.ppp1.password);
        /* Display all ppp1 Mobile carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Mobile.apn_num; i++)
        {
            printf(" ppp1    \tMobile  \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Mobile.apn[i],
                   apnMsg.ppp1.Mobile.user[i], apnMsg.ppp1.Mobile.password[i]);
            j++;
        }

        /* Display all ppp1 Unicom carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Unicom.apn_num; i++)
        {
            printf(" ppp1    \tUnicom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Unicom.apn[i],
                   apnMsg.ppp1.Unicom.user[i], apnMsg.ppp1.Unicom.password[i]);
            j++;
        }

        /* Display all ppp1 Telecom carrier APNs */
        for (int i = 0; i < apnMsg.ppp1.Telecom.apn_num; i++)
        {
            printf(" ppp1    \tTelecom   \t%d\t%-15s\t%-15s\t%s\n", j, apnMsg.ppp1.Telecom.apn[i],
                   apnMsg.ppp1.Telecom.user[i], apnMsg.ppp1.Telecom.password[i]);
            j++;
        }
    }
    else
    {
        /* Invalid device parameter provided */
        return FALSE;
    }

    return TRUE;
}

/**
 * @brief Delete a specific APN configuration by sequence number
 * 
 * This function deletes a specific APN configuration identified by its sequence number
 * Does not support deletion of default APN configurations
 * Handles deletion from Mobile, Unicom, and Telecom carrier arrays
 * 
 * @param dev Device name ("ppp0" or "ppp1")
 * @param num Sequence number of the APN to delete
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
uint8_t wwan_apn_delete_one(char *dev, char *num)
{
    /* Static buffer to hold JSON configuration string */
    static uint8_t CONFIG_STRING[JSON_LEN];
    /* Buffer for writing formatted JSON configuration */
    char config_write_buff[JSON_LEN];

    /* Clear configuration string buffer before use */
    memset(CONFIG_STRING, 0x00, JSON_LEN);
    /* Retrieve current configuration from storage */
    if (!getConfig(CONFIG_STRING, CONFIG_APN))
    {
        printf("ERROR: getConfig failed!\n");
        return FALSE;
    }

    /* Parse JSON configuration string into cJSON object */
    cJSON *config = string2Json(CONFIG_STRING);
    if (config == NULL)
    {
        return FALSE;
    }

    /* Get device-specific configuration object */
    cJSON *device_item = cJSON_GetObjectItem(config, dev);
    if (device_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    // Mobile carrier configuration
    /* Get Mobile carrier configuration object */
    cJSON *Mobile_item = cJSON_GetObjectItem(device_item, "Mobile");
    if (Mobile_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier APN array */
    cJSON *Mobile_apn = cJSON_GetObjectItem(Mobile_item, "apn");
    if (Mobile_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get number of Mobile carrier APNs */
    int Mobile_apn_num = cJSON_GetArraySize(Mobile_apn);

    /* Get Mobile carrier username array */
    cJSON *Mobile_user = cJSON_GetObjectItem(Mobile_item, "user");
    if (Mobile_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Mobile carrier password array */
    cJSON *Mobile_passd = cJSON_GetObjectItem(Mobile_item, "passd");
    if (Mobile_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    // Unicom carrier configuration
    /* Get Unicom carrier configuration object */
    cJSON *Unicom_item = cJSON_GetObjectItem(device_item, "Unicom");
    if (Unicom_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier APN array */
    cJSON *Unicom_apn = cJSON_GetObjectItem(Unicom_item, "apn");
    if (Unicom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get number of Unicom carrier APNs */
    int Unicom_apn_num = cJSON_GetArraySize(Unicom_apn);

    /* Get Unicom carrier username array */
    cJSON *Unicom_user = cJSON_GetObjectItem(Unicom_item, "user");
    if (Unicom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Unicom carrier password array */
    cJSON *Unicom_passd = cJSON_GetObjectItem(Unicom_item, "passd");
    if (Unicom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    // Telecom carrier configuration
    /* Get Telecom carrier configuration object */
    cJSON *Telecom_item = cJSON_GetObjectItem(device_item, "Telecom");
    if (Telecom_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier APN array */
    cJSON *Telecom_apn = cJSON_GetObjectItem(Telecom_item, "apn");
    if (Telecom_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get number of Telecom carrier APNs */
    int Telecom_apn_num = cJSON_GetArraySize(Telecom_apn);

    /* Get Telecom carrier username array */
    cJSON *Telecom_user = cJSON_GetObjectItem(Telecom_item, "user");
    if (Telecom_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get Telecom carrier password array */
    cJSON *Telecom_passd = cJSON_GetObjectItem(Telecom_item, "passd");
    if (Telecom_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    // Determine position and delete the specified APN
    /* Check if position is within Mobile carrier range */
    if ((0 < atoi(num)) && (atoi(num) <= Mobile_apn_num))
    {
        /* Position is in "Mobile" carrier array */
        cJSON_DeleteItemFromArray(Mobile_apn, atoi(num) - 1);
        cJSON_DeleteItemFromArray(Mobile_user, atoi(num) - 1);
        cJSON_DeleteItemFromArray(Mobile_passd, atoi(num) - 1);
    }
    /* Check if position is within Unicom carrier range */
    else if ((Mobile_apn_num < atoi(num)) && (atoi(num) <= (Mobile_apn_num + Unicom_apn_num)))
    {
        /* Position is in "Unicom" carrier array */
        cJSON_DeleteItemFromArray(Unicom_apn, atoi(num) - Mobile_apn_num - 1);
        cJSON_DeleteItemFromArray(Unicom_user, atoi(num) - Mobile_apn_num - 1);
        cJSON_DeleteItemFromArray(Unicom_passd, atoi(num) - Mobile_apn_num - 1);
    }
    /* Check if position is within Telecom carrier range */
    else if (((Mobile_apn_num + Unicom_apn_num) < atoi(num)) &&
             (atoi(num) <= (Mobile_apn_num + Unicom_apn_num + Telecom_apn_num)))
    {
        /* Position is in "Telecom" carrier array */
        cJSON_DeleteItemFromArray(Telecom_apn, atoi(num) - Mobile_apn_num - Unicom_apn_num - 1);
        cJSON_DeleteItemFromArray(Telecom_user, atoi(num) - Mobile_apn_num - Unicom_apn_num - 1);
        cJSON_DeleteItemFromArray(Telecom_passd, atoi(num) - Mobile_apn_num - Unicom_apn_num - 1);
    }
    /* Validate that position is within acceptable range */
    else if ((atoi(num) > 12) || (atoi(num) >= (Mobile_apn_num + Unicom_apn_num + Telecom_apn_num)))
    {
        printf("parameter exceeds range\n");
        cJSON_Delete(config);
        return FALSE;
    }

    /* Clear write buffer before generating JSON string */
    memset(config_write_buff, 0x00, sizeof(config_write_buff));
    int size = sizeof(config_write_buff);
    /* Generate formatted JSON string with proper formatting */
    cJSON_PrintPreallocated(config, config_write_buff, (const int)size, 1);

    /* Write updated configuration back to storage */
    if (write_file(CONFIG_APN, config_write_buff) < 0)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Inform user of successful deletion */
    printf("apn %s %d delete success\n", dev, atoi(num));

    /* Clean up cJSON objects to prevent memory leaks */
    cJSON_Delete(config);
    return TRUE;
}

/**
 * @brief Delete all APN configurations for a specific carrier
 * 
 * This function deletes all APN configurations for a specified carrier
 * Clears all APNs, usernames, and passwords for the given carrier
 * Supports Mobile, Unicom, and Telecom carriers
 * 
 * @param dev Device name ("ppp0" or "ppp1")
 * @param carrier_name Carrier name ("Mobile", "Unicom", or "Telecom")
 * @return uint8_t Returns TRUE on success, FALSE on failure
 */
uint8_t wwan_apn_delete_carrier(char *dev, char *carrier_name)
{
    /* Static buffer to hold JSON configuration string */
    static uint8_t CONFIG_STRING[JSON_LEN];
    /* Buffer for writing formatted JSON configuration */
    char config_write_buff[JSON_LEN];

    /* Clear configuration string buffer before use */
    memset(CONFIG_STRING, 0x00, JSON_LEN);
    /* Retrieve current configuration from storage */
    if (!getConfig(CONFIG_STRING, CONFIG_APN))
    {
        printf("ERROR: getConfig failed!\n");
        return FALSE;
    }

    /* Parse JSON configuration string into cJSON object */
    cJSON *config = string2Json(CONFIG_STRING);
    if (config == NULL)
    {
        return FALSE;
    }

    /* Get device-specific configuration object */
    cJSON *device_item = cJSON_GetObjectItem(config, dev);
    if (device_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get carrier-specific configuration object */
    cJSON *carrier_item = cJSON_GetObjectItem(device_item, carrier_name);
    if (carrier_item == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get carrier APN array */
    cJSON *carrier_apn = cJSON_GetObjectItem(carrier_item, "apn");
    if (carrier_apn == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get number of carrier APNs */
    int carrier_apn_num = cJSON_GetArraySize(carrier_apn);

    /* Get carrier username array */
    cJSON *carrier_user = cJSON_GetObjectItem(carrier_item, "user");
    if (carrier_user == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Get carrier password array */
    cJSON *carrier_passd = cJSON_GetObjectItem(carrier_item, "passd");
    if (carrier_passd == NULL)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Delete all APN configurations for the specified carrier */
    while (carrier_apn_num--)
    {
        cJSON_DeleteItemFromArray(carrier_apn, 0);
        cJSON_DeleteItemFromArray(carrier_user, 0);
        cJSON_DeleteItemFromArray(carrier_passd, 0);
    }

    /* Clear write buffer before generating JSON string */
    memset(config_write_buff, 0x00, sizeof(config_write_buff));
    int size = sizeof(config_write_buff);
    /* Generate formatted JSON string with proper formatting */
    cJSON_PrintPreallocated(config, config_write_buff, (const int)size, 1);

    /* Write updated configuration back to storage */
    if (write_file(CONFIG_APN, config_write_buff) < 0)
    {
        cJSON_Delete(config);
        return FALSE;
    }

    /* Inform user of successful deletion */
    printf("%s's apn of %s delete success\n", carrier_name, dev);

    /* Clean up cJSON objects to prevent memory leaks */
    cJSON_Delete(config);

    return TRUE;
}